package com.hzp.net.netty.server.handler;

import com.hzp.net.netty.server.handler.custom.CustomDecoder;
import com.hzp.net.netty.server.handler.custom.CutsomServerHandler;
import com.hzp.net.netty.server.handler.http.NettyHttpHandler;
import com.hzp.net.netty.server.handler.ws.WebSocketFrameHandler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 协议选择器，支持动态协议HTTP WEBSOCKET TCP私有协议
 */
@Slf4j
public class ProtocolSelectorHandler extends ByteToMessageDecoder {

    private static final int MAX_CONTENT_LENGTH = 8192;

    /**
     * WebSocket定义请求行前缀
     */
    private static final String WEB_SOCKET_LINE_PREFIX = "GET /ws";
    /**
     * WebSocket的uri
     */
    private static final String WEB_SOCKET_PREFIX = "/ws";
    /**
     * 检查10个字节，没有空格就是自定义协议
     */
    private static final int SPACE_LENGTH = 10;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        if (isWebSocketProtocol(in)) {
            log.debug("Protocol is WebSocket");
            addWebSocketHandlers(ctx.pipeline());
        } else if (isHttpProtocol(in)) {
            log.debug("Protocol is Http");
            addHttpHandlers(ctx.pipeline());
        } else if (isCustomProtocol(in)) {
            log.debug("Protocol is Custom");
            addCustomProtocolHandlers(ctx.pipeline());
        } else {
            log.debug("Protocol is Socket");
            addHttpHandlers(ctx.pipeline());
        }
        ctx.pipeline().remove(this);
    }


    /**
     * 判断是WebSocket协议
     *
     * @param byteBuf
     * @return
     */
    private boolean isWebSocketProtocol(ByteBuf byteBuf) {
        if (byteBuf.readableBytes() < WEB_SOCKET_LINE_PREFIX.length()) {
            return false;
        }
        byteBuf.markReaderIndex();
        byte[] content = new byte[WEB_SOCKET_LINE_PREFIX.length()];
        byteBuf.readBytes(content);
        byteBuf.resetReaderIndex();
        String s = new String(content, CharsetUtil.UTF_8);
        return s.equals(WEB_SOCKET_LINE_PREFIX);
    }

    /**
     * 增加WebSocket处理
     *
     * @param pipeline
     */
    private void addWebSocketHandlers(ChannelPipeline pipeline) {
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new HttpObjectAggregator(MAX_CONTENT_LENGTH));
        pipeline.addLast(new WebSocketServerProtocolHandler(WEB_SOCKET_PREFIX));
        pipeline.addLast(new WebSocketFrameHandler());
    }

    /**
     * 是否是http协议
     *
     * @param byteBuf
     * @return
     */
    private boolean isHttpProtocol(ByteBuf byteBuf) {
        if (byteBuf.readableBytes() < 5) {
            return false;
        }
        final int magic1 = byteBuf.getUnsignedByte(byteBuf.readerIndex());
        final int magic2 = byteBuf.getUnsignedByte(byteBuf.readerIndex() + 1);
        return magic1 == 'G' && magic2 == 'E' || // GET
                magic1 == 'P' && magic2 == 'O' || // POST
                magic1 == 'P' && magic2 == 'U' || // PUT
                magic1 == 'H' && magic2 == 'E' || // HEAD
                magic1 == 'O' && magic2 == 'P' || // OPTIONS
                magic1 == 'P' && magic2 == 'A' || // PATCH
                magic1 == 'D' && magic2 == 'E' || // DELETE
                magic1 == 'T' && magic2 == 'R' || // TRACE
                magic1 == 'C' && magic2 == 'O';   // CONNECT
    }


    /**
     * 增加http处理
     *
     * @param pipeline
     */
    private void addHttpHandlers(ChannelPipeline pipeline) {
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new HttpObjectAggregator(MAX_CONTENT_LENGTH));
        pipeline.addLast(new NettyHttpHandler());
    }

    /**
     * 是否是自定义协议
     *
     * @param byteBuf
     * @return
     */
    private boolean isCustomProtocol(ByteBuf byteBuf) {
        byteBuf.markReaderIndex();
        byte[] content = new byte[SPACE_LENGTH];
        byteBuf.readBytes(content);
        byteBuf.resetReaderIndex();
        String s = new String(content, CharsetUtil.UTF_8);
        return s.indexOf(" ") == -1;
    }

    /**
     * 增加自定义协议处理
     *
     * @param pipeline
     */
    private void addCustomProtocolHandlers(ChannelPipeline pipeline) {
        pipeline.addLast(new CustomDecoder(1024, 1, 4));//这里1代表长度属性是从索引1位置开始的，4代表有4个字节的长度
        pipeline.addLast(new CutsomServerHandler());
    }


}
